{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab0a8578",
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.home\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f7c7831",
   "metadata": {},
   "outputs": [],
   "source": [
    "import spinal.core._\n",
    "\n",
    "import spinal.lib.bus.amba3.apb._\n",
    "import spinal.lib.bus.amba3.ahblite._\n",
    "\n",
    "import spinal.lib.bus.amba4.axi._ \n",
    "import spinal.lib.bus.amba4.axis._\n",
    "\n",
    "import spinal.lib.bus.regif._\n",
    "import spinal.lib.bus.regif.Document._\n",
    "import spinal.lib.bus.regif.AccessType._\n",
    "\n",
    "import spinal.lib.bus.misc._\n",
    "import spinal.core.sim._\n",
    "\n",
    "import spinal.lib.fsm._\n",
    "\n",
    "import spinal.lib.soc.pinsec._\n",
    "\n",
    "import spinal.lib.Stream._\n",
    "\n",
    "import scala.math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0264d49",
   "metadata": {},
   "outputs": [],
   "source": [
    "case class Xilinx7serial_pcie_cfg_status() extends Bundle{\n",
    "    val s_status                                       = in Bits(16 bits)\n",
    "    val s_command                                      = in Bits(16 bits)\n",
    "    val s_dstatus                                      = in Bits(16 bits)\n",
    "    val s_dcommand                                     = in Bits(16 bits)\n",
    "    val s_lstatus                                      = in Bits(16 bits)\n",
    "    val s_lcommand                                     = in Bits(16 bits)\n",
    "    val s_dcommand2                                    = in Bits(16 bits)\n",
    "    val s_pcie_link_state                              = in Bits(3 bits)\n",
    "    val s_pmcsr_pme_en                                 = in Bool()\n",
    "    val s_pmcsr_powerstate                             = in Bits(2 bits)\n",
    "    val s_pmcsr_pme_status                             = in Bool()\n",
    "    val s_received_func_lvl_rst                        = in Bool()\n",
    "    val s_turnoff                                      = in Bool()\n",
    "    val s_bus_number                                   = in Bits(8 bits)\n",
    "    val s_device_number                                = in Bits(5 bits)\n",
    "    val s_function_number                              = in Bits(3 bits)\n",
    "    val s_bridge_serr_en                               = in Bool()\n",
    "    val s_slot_control_electromech_il_ctl_pulse        = in Bool()\n",
    "    val s_root_control_syserr_corr_err_en              = in Bool()\n",
    "    val s_root_control_syserr_non_fatal_err_en         = in Bool()\n",
    "    val s_root_control_syserr_fatal_err_en             = in Bool()\n",
    "    val s_root_control_pme_int_en                      = in Bool()\n",
    "    val s_aer_rooterr_corr_err_reporting_en            = in Bool()\n",
    "    val s_aer_rooterr_non_fatal_err_reporting_en       = in Bool()\n",
    "    val s_aer_rooterr_fatal_err_reporting_en           = in Bool()\n",
    "    val s_aer_rooterr_corr_err_received                = in Bool()\n",
    "    val s_aer_rooterr_non_fatal_err_received           = in Bool()\n",
    "    val s_aer_rooterr_fatal_err_received               = in Bool()\n",
    "    val s_vc_tcvc_map                                  = in Bits(7 bits)\n",
    "    val s_tx_buf_av                                    = in Bits(6 bits)\n",
    "    val s_tx_err_drop                                  = in Bool()\n",
    "    val s_tx_cfg_req                                   = in Bool()\n",
    "\n",
    "    s_status                                 .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status status\" )\n",
    "    s_command                                .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status command\" )\n",
    "    s_dstatus                                .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status dstatus\" )\n",
    "    s_dcommand                               .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status dcommand\" )\n",
    "    s_lstatus                                .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status lstatus\" )\n",
    "    s_lcommand                               .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status lcommand\" )\n",
    "    s_dcommand2                              .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status dcommand2\" )\n",
    "    s_pcie_link_state                        .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status pcie_link_state\" )\n",
    "    s_pmcsr_pme_en                           .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status pmcsr_pme_en\" )\n",
    "    s_pmcsr_powerstate                       .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status pmcsr_powerstate\" )\n",
    "    s_pmcsr_pme_status                       .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status pmcsr_pme_status\" )\n",
    "    s_received_func_lvl_rst                  .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status received_func_lvl_rst\" )\n",
    "    s_turnoff                                .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status turnoff\" )\n",
    "    s_bus_number                             .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status bus_number\" )\n",
    "    s_device_number                          .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status device_number\" )\n",
    "    s_function_number                        .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status function_number\" )\n",
    "    s_bridge_serr_en                         .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status bridge_serr_en\" )\n",
    "    s_slot_control_electromech_il_ctl_pulse  .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status slot_control_electromech_il_ctl_pulse\" )\n",
    "    s_root_control_syserr_corr_err_en        .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status root_control_syserr_corr_err_en\" )\n",
    "    s_root_control_syserr_non_fatal_err_en   .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status root_control_syserr_non_fatal_err_en\" )\n",
    "    s_root_control_syserr_fatal_err_en       .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status root_control_syserr_fatal_err_en\" )\n",
    "    s_root_control_pme_int_en                .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status root_control_pme_int_en\" )\n",
    "    s_aer_rooterr_corr_err_reporting_en      .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status aer_rooterr_corr_err_reporting_en\" )\n",
    "    s_aer_rooterr_non_fatal_err_reporting_en .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status aer_rooterr_non_fatal_err_reporting_en\" )\n",
    "    s_aer_rooterr_fatal_err_reporting_en     .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status aer_rooterr_fatal_err_reporting_en\" )\n",
    "    s_aer_rooterr_corr_err_received          .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status aer_rooterr_corr_err_received\" )\n",
    "    s_aer_rooterr_non_fatal_err_received     .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status aer_rooterr_non_fatal_err_received\" )\n",
    "    s_aer_rooterr_fatal_err_received         .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status aer_rooterr_fatal_err_received\" )\n",
    "    s_vc_tcvc_map                            .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status vc_tcvc_map\" )\n",
    "    s_tx_buf_av                              .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status tx_buf_av\" )\n",
    "    s_tx_err_drop                            .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status tx_err_drop\" )\n",
    "    s_tx_cfg_req                             .addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:pcie2_cfg_status:1.0 pcie2_cfg_status tx_cfg_req\" )\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d52cb373",
   "metadata": {},
   "outputs": [],
   "source": [
    "/**\n",
    "  * Dma commander definition\n",
    "  */\n",
    "case class DmaCmdInterface(dataWidth: Int , resultWidth : Int ) extends Bundle with IMasterSlave {\n",
    "    val data         = in  Bits(dataWidth*8 bits)\n",
    "    val command      = in  Bits(32 bits)\n",
    "    val cmd_result   = out Bits(resultWidth*8 bits)\n",
    "\n",
    "\n",
    "    /** Set the direction of the bus when it is used as master */\n",
    "    override def asMaster(): Unit = {\n",
    "        in (cmd_result)\n",
    "        out(data , command)\n",
    "    }\n",
    "\n",
    "    /**\n",
    "    * Connect two Dma commander together Master >> Slave\n",
    "    */\n",
    "    def >> (sink: DmaCmdInterface): Unit = {\n",
    "        sink.data        := this.data\n",
    "        sink.command     := this.command\n",
    "        this.cmd_result := sink.cmd_result\n",
    "    }\n",
    "\n",
    "    /** Slave << Master */\n",
    "    def << (sink: DmaCmdInterface): Unit = sink >> this\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "961df8d8",
   "metadata": {},
   "outputs": [],
   "source": [
    "class CommandBus(dataWidth: Int , resultWidth : Int  ) extends Component {\n",
    "    val io = new Bundle {\n",
    "        val ctrl       =  DmaCmdInterface(dataWidth=dataWidth , resultWidth=resultWidth)\n",
    "        val cmd        =  master(Axi4Stream(Axi4StreamConfig(dataWidth = dataWidth )))\n",
    "        val sts        =  slave (Axi4Stream(Axi4StreamConfig(dataWidth = resultWidth,useKeep=true,useLast=true)))\n",
    "    }\n",
    "\n",
    "    io.ctrl.cmd_result.setAsReg()\n",
    "    io.ctrl.cmd_result.init(0)\n",
    "\n",
    "    io.sts.ready := Bool(false)\n",
    "    io.cmd.valid := Bool(false)\n",
    "    io.cmd.payload.assignFromBits(io.ctrl.data)\n",
    "\n",
    "    val stateMachine = new StateMachine {\n",
    "        val idle = new State with EntryPoint\n",
    "        val writeData = new State\n",
    "        val waitClean = new State\n",
    "\n",
    "        idle.whenIsActive {\n",
    "            io.cmd.valid   := False\n",
    "            io.sts.ready   := Bool(false)\n",
    "            when( (io.ctrl.command(0)) && (io.ctrl.cmd_result === 0) ) {\n",
    "                goto(writeData)\n",
    "            }\n",
    "        }\n",
    "\n",
    "        writeData.whenIsActive {\n",
    "            io.cmd.valid   := True\n",
    "            io.cmd.payload.assignFromBits(io.ctrl.data)\n",
    "            when(io.cmd.fire) {\n",
    "                goto(waitClean)\n",
    "            }\n",
    "        }\n",
    "\n",
    "        waitClean.whenIsActive {\n",
    "            io.cmd.valid   := False\n",
    "            when( ! io.ctrl.command(0) ) {\n",
    "                io.ctrl.cmd_result := 0;\n",
    "                goto(idle)\n",
    "            }\n",
    "\n",
    "            io.sts.ready := Bool(true)\n",
    "\n",
    "            when(io.sts.fire) {\n",
    "                //io.ctrl.cmd_result := io.sts.payload.asBits\n",
    "                io.ctrl.cmd_result := io.sts.data.asBits\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6ae5e74c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "class DmaControler extends Component{\n",
    "    val io = new Bundle{\n",
    "        val mm2s_ctrl    =  DmaCmdInterface( dataWidth = 9 , resultWidth = 1)\n",
    "        val mm2s_cmd     =  master(Axi4Stream(Axi4StreamConfig(dataWidth=9)))\n",
    "        val mm2s_sts     =  slave (Axi4Stream(Axi4StreamConfig(dataWidth=1,useKeep=true,useLast=true)))\n",
    "\n",
    "        val s2mm_ctrl    =  DmaCmdInterface( dataWidth = 9 , resultWidth = 4 )\n",
    "        val s2mm_cmd     =  master(Axi4Stream(Axi4StreamConfig(dataWidth=9)))\n",
    "        val s2mm_sts     =  slave (Axi4Stream(Axi4StreamConfig(dataWidth=4,useKeep=true,useLast=true)))\n",
    "    }\n",
    "\n",
    "\n",
    "    val mm2s_chanel       = new CommandBus(dataWidth = 9 ,  resultWidth = 1 )\n",
    "    mm2s_chanel.io.ctrl   << io.mm2s_ctrl\n",
    "    mm2s_chanel.io.cmd    >> io.mm2s_cmd\n",
    "    mm2s_chanel.io.sts    << io.mm2s_sts\n",
    "\n",
    "    val s2mm_chanel       = new CommandBus(dataWidth = 9 ,  resultWidth = 4 )\n",
    "    s2mm_chanel.io.ctrl   << io.s2mm_ctrl\n",
    "    s2mm_chanel.io.cmd    >> io.s2mm_cmd\n",
    "    s2mm_chanel.io.sts    << io.s2mm_sts\n",
    "}\n",
    "\n",
    "showRtl( new  DmaControler() )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "246b7d9e",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Axi4Ex ( config : Axi4Config ) extends Axi4( config  )\n",
    "{\n",
    "    def addInterfaceParam () {\n",
    "        if(isSlaveInterface)\n",
    "        {\n",
    "            aw.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWVALID\")\n",
    "            aw.ready.addAttribute(\"X_INTERFACE_INFO\" ,\"xilinx.com:interface:aximm:1.0 s_axi4 AWREADY\" )\n",
    "            aw.payload.addr.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWADDR\")\n",
    "            aw.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWID\")\n",
    "            aw.payload.region.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWREGION\")\n",
    "            aw.payload.len.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWLEN\")\n",
    "            aw.payload.size.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWSIZE\")\n",
    "            aw.payload.burst.addAttribute(\"X_INTERFACE_INFO\" ,\"xilinx.com:interface:aximm:1.0 s_axi4 AWBURST\" )\n",
    "            aw.payload.lock.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWLOCK\")\n",
    "            aw.payload.cache.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWCACHE\")\n",
    "            aw.payload.qos.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWQOS\")\n",
    "            aw.payload.prot.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 AWPROT\")\n",
    "\n",
    "\n",
    "            w.valid.addAttribute(\"X_INTERFACE_INFO\" ,\"xilinx.com:interface:aximm:1.0 s_axi4 WVALID\" )\n",
    "            w.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 WREADY\")\n",
    "            w.payload.data.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 WDATA\")\n",
    "            w.payload.strb.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 WSTRB\")\n",
    "            w.payload.last.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 WLAST\")\n",
    "\n",
    "\n",
    "            b.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 BVALID\")\n",
    "            b.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 BREADY\")\n",
    "            b.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 BID\")\n",
    "            b.payload.resp.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 BRESP\")\n",
    "\n",
    "            ar.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARVALID\")\n",
    "            ar.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARREADY\")\n",
    "            ar.payload.addr.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARADDR\")\n",
    "            ar.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARID\")\n",
    "            ar.payload.region.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARREGION\")\n",
    "            ar.payload.len.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARLEN\")\n",
    "            ar.payload.size.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARSIZE\")\n",
    "            ar.payload.burst.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARBURST\")\n",
    "            ar.payload.lock.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARLOCK\")\n",
    "            ar.payload.cache.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARCACHE\")\n",
    "            ar.payload.qos.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARQOS\")\n",
    "            ar.payload.prot.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 ARPROT\")\n",
    "\n",
    "            r.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 RVALID\")\n",
    "            r.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 RREADY\")\n",
    "            r.payload.data.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 RDATA\")\n",
    "            r.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 RID\")\n",
    "            r.payload.resp.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 RRESP\")\n",
    "            r.payload.last.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 s_axi4 RLAST\")\n",
    "        } else {\n",
    "            aw.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWVALID\")\n",
    "            aw.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWVALID\")\n",
    "            aw.ready.addAttribute(\"X_INTERFACE_INFO\" ,\"xilinx.com:interface:aximm:1.0 m_axi4 AWREADY\" )\n",
    "            aw.payload.addr.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWADDR\")\n",
    "            aw.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWID\")\n",
    "            aw.payload.region.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWREGION\")\n",
    "            aw.payload.len.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWLEN\")\n",
    "            aw.payload.size.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWSIZE\")\n",
    "            aw.payload.burst.addAttribute(\"X_INTERFACE_INFO\" ,\"xilinx.com:interface:aximm:1.0 m_axi4 AWBURST\" )\n",
    "            aw.payload.lock.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWLOCK\")\n",
    "            aw.payload.cache.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWCACHE\")\n",
    "            aw.payload.qos.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWQOS\")\n",
    "            aw.payload.prot.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 AWPROT\")\n",
    "\n",
    "\n",
    "            w.valid.addAttribute(\"X_INTERFACE_INFO\" ,\"xilinx.com:interface:aximm:1.0 m_axi4 WVALID\" )\n",
    "            w.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 WREADY\")\n",
    "            w.payload.data.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 WDATA\")\n",
    "            w.payload.strb.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 WSTRB\")\n",
    "            w.payload.last.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 WLAST\")\n",
    "\n",
    "\n",
    "            b.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 BVALID\")\n",
    "            b.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 BREADY\")\n",
    "            b.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 BID\")\n",
    "            b.payload.resp.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 BRESP\")\n",
    "\n",
    "            ar.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARVALID\")\n",
    "            ar.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARREADY\")\n",
    "            ar.payload.addr.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARADDR\")\n",
    "            ar.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARID\")\n",
    "            ar.payload.region.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARREGION\")\n",
    "            ar.payload.len.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARLEN\")\n",
    "            ar.payload.size.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARSIZE\")\n",
    "            ar.payload.burst.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARBURST\")\n",
    "            ar.payload.lock.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARLOCK\")\n",
    "            ar.payload.cache.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARCACHE\")\n",
    "            ar.payload.qos.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARQOS\")\n",
    "            ar.payload.prot.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 ARPROT\")\n",
    "\n",
    "            r.valid.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 RVALID\")\n",
    "            r.ready.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 RREADY\")\n",
    "            r.payload.data.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 RDATA\")\n",
    "            r.payload.id.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 RID\")\n",
    "            r.payload.resp.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 RRESP\")\n",
    "            r.payload.last.addAttribute(\"X_INTERFACE_INFO\" , \"xilinx.com:interface:aximm:1.0 m_axi4 RLAST\")\n",
    "        }\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c9ce84fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "def addInterfaceInfo[T <:Data]( s:Stream[T] )\n",
    "{\n",
    "    s.valid.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TVALID\")\n",
    "    s.ready.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TREADY\")\n",
    "    s.data .addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDATA\")\n",
    "    if(s.id   != null) s.id.addAttribute  (\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TID\")\n",
    "    if(s.strb != null) s.strb.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TSTRB\")\n",
    "    if(s.keep != null) s.keep.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com;interface:axis:1.0 ${s.getName()} TKEEP\")\n",
    "    if(s.last != null) s.last.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TLAST\")\n",
    "    if(s.dest != null) s.dest.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDEST\")\n",
    "    if(s.user != null) s.user.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TUSER\")\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b7fbde7e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def addInterfaceInfo[T <:Data]( s:Stream[T] ) \n",
    "{\n",
    "    s.valid.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TVALID\")\n",
    "    s.ready.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TREADY\")\n",
    "\n",
    "    s.payload match\n",
    "    {\n",
    "        case x: Axi4Stream.Axi4StreamBundle =>\n",
    "        {\n",
    "            x.data.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDATA\")\n",
    "            if(x.id   != null) x.id.addAttribute  (\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TID\")\n",
    "            if(x.strb != null) x.strb.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TSTRB\")\n",
    "            if(x.keep != null) x.keep.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TKEEP\")\n",
    "            if(x.last != null) x.last.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TLAST\")\n",
    "            if(x.dest != null) x.dest.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDEST\")\n",
    "            if(x.user != null) x.user.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TUSER\")\n",
    "        }\n",
    "        case _ =>\n",
    "        {\n",
    "            s.payload.addAttribute (\"X INTERFACE INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDATA\")\n",
    "        }\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1edd026",
   "metadata": {},
   "outputs": [],
   "source": [
    "def addInterfaceInfo[T <:Data]( s:Stream[T] ) \n",
    "{\n",
    "    s.valid.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TVALID\")\n",
    "    s.ready.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TREADY\")\n",
    "    s.payload match\n",
    "    {\n",
    "        case x: Axi4Stream.Axi4StreamBundle =>\n",
    "        {\n",
    "            x.data.addAttribute(\"X_INTERFACE_INFO\"  , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDATA\")\n",
    "            if(x.config.useId) x.id.addAttribute  (\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TID\")\n",
    "            if(x.config.useStrb) x.strb.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TSTRB\")\n",
    "            if(x.config.useKeep) x.keep.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TKEEP\")\n",
    "            if(x.config.useLast) x.last.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TLAST\")\n",
    "            if(x.config.useDest) x.dest.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDEST\")\n",
    "            if(x.config.useUser) x.user.addAttribute(\"X_INTERFACE_INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TUSER\")\n",
    "        }\n",
    "        case _ =>\n",
    "        {\n",
    "            s.payload.addAttribute (\"X INTERFACE INFO\" , s\"xilinx.com:interface:axis:1.0 ${s.getName()} TDATA\")\n",
    "        }\n",
    "    }\n",
    "\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7111db3d",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "class Pcie_Contrlor extends Component{\n",
    "    val io = new Bundle{\n",
    "        val pcie_cfg     =  Xilinx7serial_pcie_cfg_status()\n",
    "\n",
    "        val axi4_bus     =  slave(new Axi4Ex(Axi4Config(addressWidth=16 , dataWidth=32 , idWidth=6)))\n",
    "        axi4_bus.addInterfaceParam()\n",
    "\n",
    "        val mm2s_cmd     =  master(Axi4Stream(Axi4StreamConfig(dataWidth=9)))\n",
    "        val mm2s_sts     =  slave (Axi4Stream(Axi4StreamConfig(dataWidth=1,useKeep=true,useLast=true)))\n",
    "\n",
    "        val s2mm_cmd     =  master(Axi4Stream(Axi4StreamConfig(dataWidth=9)))\n",
    "        val s2mm_sts     =  slave (Axi4Stream(Axi4StreamConfig(dataWidth=4,useKeep=true,useLast=true)))\n",
    "        \n",
    "        val pcie_usr_lnk_up  = in Bool()\n",
    "        val pcie_usr_app_rdy = in Bool()\n",
    "    }\n",
    "\n",
    "    addInterfaceInfo(io.mm2s_cmd)\n",
    "    addInterfaceInfo(io.mm2s_sts)\n",
    "    addInterfaceInfo(io.s2mm_cmd)\n",
    "    addInterfaceInfo(io.s2mm_sts)\n",
    "\n",
    "    // mm2s channel\n",
    "    val mm2s_start_address   = RegInit(U\"32'h0\")\n",
    "    val mm2s_bytes_transfer  = RegInit(U\"32'h0\")\n",
    "    val mm2s_tag             = RegInit(U\"32'h0\")\n",
    "    val mm2s_cmd_data        = U\"4'h0\" ## \n",
    "                                mm2s_tag(3 downto 0) ## \n",
    "                                mm2s_start_address ## \n",
    "                                U\"1'b0\" ##                 // DRR\n",
    "                                U\"1'b1\" ##                 // EOF\n",
    "                                U\"6'b000000\" ##            // DSA\n",
    "                                U\"1'b1\" ##                 // type 1:incr 0:fixed\n",
    "                                mm2s_bytes_transfer(22 downto 0)\n",
    "\n",
    "\n",
    "    // s2mm channel\n",
    "    val s2mm_start_address   = RegInit(U\"32'h0\")\n",
    "    val s2mm_bytes_transfer  = RegInit(U\"32'h0\")\n",
    "    val s2mm_tag             = RegInit(U\"32'h0\")\n",
    "    val s2mm_cmd_data        = U\"4'h0\" ## \n",
    "                                s2mm_tag(3 downto 0) ## \n",
    "                                s2mm_start_address ## \n",
    "                                U\"1'b0\" ##                 // DRR\n",
    "                                U\"1'b1\" ##                 // EOF\n",
    "                                U\"6'b000000\" ##            // DSA\n",
    "                                U\"1'b1\" ##                 // type 1:incr 0:fixed\n",
    "                                s2mm_bytes_transfer(22 downto 0)\n",
    "\n",
    "\n",
    "    // dma controler\n",
    "    val dma_ctrl    =  new DmaControler()\n",
    "    dma_ctrl.io.mm2s_ctrl.data    := mm2s_cmd_data\n",
    "    dma_ctrl.io.s2mm_ctrl.data    := s2mm_cmd_data\n",
    "\n",
    "\n",
    "    // 建立一个被io.bus驱动的 axi4SlaveFactory实例\n",
    "    val busCtrl = Axi4SlaveFactory(io.axi4_bus)\n",
    "    busCtrl.driveAndRead  ( mm2s_start_address               , address = 0x100, documentation=\"mm2s start address\")\n",
    "    busCtrl.driveAndRead  ( mm2s_bytes_transfer              , address = 0x104, documentation=\"mm2s transfer bytes\")\n",
    "    busCtrl.driveAndRead  ( mm2s_tag                         , address = 0x108, documentation=\"mm2s tag\")\n",
    "    busCtrl.driveAndRead  ( dma_ctrl.io.mm2s_ctrl.command    , address = 0x10c, documentation=\"mm2s command 1:send cmd 2:clean\") \n",
    "    busCtrl.read          ( dma_ctrl.io.mm2s_ctrl.cmd_result , address = 0x110, documentation=\"mm2s sts result\")\n",
    "\n",
    "    busCtrl.driveAndRead  ( s2mm_start_address               , address = 0x120, documentation=\"s2mm start address\")\n",
    "    busCtrl.driveAndRead  ( s2mm_bytes_transfer              , address = 0x124, documentation=\"s2mm transfer bytes\")\n",
    "    busCtrl.driveAndRead  ( s2mm_tag                         , address = 0x128, documentation=\"s2mm tag\")\n",
    "    busCtrl.driveAndRead  ( dma_ctrl.io.s2mm_ctrl.command    , address = 0x12c, documentation=\"s2mm command 1:send cmd 2:clean\") \n",
    "    busCtrl.read          ( dma_ctrl.io.s2mm_ctrl.cmd_result , address = 0x130, documentation=\"s2mm sts result\")\n",
    "\n",
    "    \n",
    "    // 请求busCtrl以在地址 0x0 创建一个读寄存器 并且 接入 s_status\n",
    "    busCtrl.read( io.pcie_cfg.s_status                                 , address = 0, documentation=\"pcie2 s_status\")\n",
    "    busCtrl.read( io.pcie_cfg.s_command                                , address = 4, documentation=\"pcie2 s_command\")\n",
    "    busCtrl.read( io.pcie_cfg.s_dstatus                                , address = 8, documentation=\"pcie2 s_dstatus\")\n",
    "    busCtrl.read( io.pcie_cfg.s_dcommand                               , address = 12, documentation=\"pcie2 s_dcommand\")\n",
    "    busCtrl.read( io.pcie_cfg.s_lstatus                                , address = 16, documentation=\"pcie2 s_lstatus\")\n",
    "    busCtrl.read( io.pcie_cfg.s_lcommand                               , address = 20, documentation=\"pcie2 s_lcommand\")\n",
    "    busCtrl.read( io.pcie_cfg.s_dcommand2                              , address = 24, documentation=\"pcie2 s_dcommand2\")\n",
    "    busCtrl.read( io.pcie_cfg.s_pcie_link_state                        , address = 28, documentation=\"pcie2 s_pcie_link_state\")\n",
    "    busCtrl.read( io.pcie_cfg.s_pmcsr_pme_en                           , address = 32, documentation=\"pcie2 s_pmcsr_pme_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_pmcsr_powerstate                       , address = 36, documentation=\"pcie2 s_pmcsr_powerstate\")\n",
    "    busCtrl.read( io.pcie_cfg.s_pmcsr_pme_status                       , address = 40, documentation=\"pcie2 s_pmcsr_pme_status\")\n",
    "    busCtrl.read( io.pcie_cfg.s_received_func_lvl_rst                  , address = 44, documentation=\"pcie2 s_received_func_lvl_rst\")\n",
    "    busCtrl.read( io.pcie_cfg.s_turnoff                                , address = 48, documentation=\"pcie2 s_turnoff\")\n",
    "    busCtrl.read( io.pcie_cfg.s_bus_number                             , address = 52, documentation=\"pcie2 s_bus_number\")\n",
    "    busCtrl.read( io.pcie_cfg.s_device_number                          , address = 56, documentation=\"pcie2 s_device_number\")\n",
    "    busCtrl.read( io.pcie_cfg.s_function_number                        , address = 60, documentation=\"pcie2 s_function_number\")\n",
    "    busCtrl.read( io.pcie_cfg.s_bridge_serr_en                         , address = 64, documentation=\"pcie2 s_bridge_serr_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_slot_control_electromech_il_ctl_pulse  , address = 68, documentation=\"pcie2 s_slot_control_electromech_il_ctl_pulse\")\n",
    "    busCtrl.read( io.pcie_cfg.s_root_control_syserr_corr_err_en        , address = 72, documentation=\"pcie2 s_root_control_syserr_corr_err_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_root_control_syserr_non_fatal_err_en   , address = 76, documentation=\"pcie2 s_root_control_syserr_non_fatal_err_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_root_control_syserr_fatal_err_en       , address = 80, documentation=\"pcie2 s_root_control_syserr_fatal_err_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_root_control_pme_int_en                , address = 84, documentation=\"pcie2 s_root_control_pme_int_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_aer_rooterr_corr_err_reporting_en      , address = 88, documentation=\"pcie2 s_aer_rooterr_corr_err_reporting_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_aer_rooterr_non_fatal_err_reporting_en , address = 92, documentation=\"pcie2 s_aer_rooterr_non_fatal_err_reporting_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_aer_rooterr_fatal_err_reporting_en     , address = 96, documentation=\"pcie2 s_aer_rooterr_fatal_err_reporting_en\")\n",
    "    busCtrl.read( io.pcie_cfg.s_aer_rooterr_corr_err_received          , address = 100, documentation=\"pcie2 s_aer_rooterr_corr_err_received\")\n",
    "    busCtrl.read( io.pcie_cfg.s_aer_rooterr_non_fatal_err_received     , address = 104, documentation=\"pcie2 s_aer_rooterr_non_fatal_err_received\")\n",
    "    busCtrl.read( io.pcie_cfg.s_aer_rooterr_fatal_err_received         , address = 108, documentation=\"pcie2 s_aer_rooterr_fatal_err_received\")\n",
    "    busCtrl.read( io.pcie_cfg.s_vc_tcvc_map                            , address = 112, documentation=\"pcie2 s_vc_tcvc_map\")\n",
    "    busCtrl.read( io.pcie_cfg.s_tx_buf_av                              , address = 116, documentation=\"pcie2 s_tx_buf_av\")\n",
    "    busCtrl.read( io.pcie_cfg.s_tx_err_drop                            , address = 120, documentation=\"pcie2 s_tx_err_drop\")\n",
    "    busCtrl.read( io.pcie_cfg.s_tx_cfg_req                             , address = 124, documentation=\"pcie2 s_tx_cfg_req\")\n",
    "    \n",
    "    busCtrl.read( io.pcie_usr_lnk_up                                      , address = 128, documentation=\"pcie2 usr_lnk_up\")\n",
    "    busCtrl.read( io.pcie_usr_app_rdy                                     , address = 132, documentation=\"pcie2 usr_app_rdy\")\n",
    "    \n",
    "    \n",
    "    busCtrl.printDataModel()\n",
    "    \n",
    "    io.mm2s_cmd    << dma_ctrl.io.mm2s_cmd\n",
    "    io.mm2s_sts    >> dma_ctrl.io.mm2s_sts\n",
    "\n",
    "    io.s2mm_cmd    << dma_ctrl.io.s2mm_cmd\n",
    "    io.s2mm_sts    >> dma_ctrl.io.s2mm_sts\n",
    "}\n",
    "\n",
    "showRtl( new  Pcie_Contrlor() )\n",
    "//showRtl(new Pcie_Contrlor().stub)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50c0856a",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
